import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;

public class Audio {
	final static Charset ENCODING = StandardCharsets.ISO_8859_1;
	static final String CUE_FILE = "..\\audio\\CuePoints.txt";
	static final String AUDIO_PATH = "..\\audio\\";
	static File[] files;

	public static void main(String[] args) {
		try {

			// 1 - Get list of captions and convert them into mp3
			files = getAudioFiles();

			if (Util.isNullObject(files)) {
				System.out.println("Can not get Audio files");
				System.exit(0);
			}
			
			print("generated lis of file names");
			// 2 - delete files
			cleanUp();
			print("cleanup completed");
			
			print("Converting text to mp3");
			for (File file : files) {
				String txt = file.getCanonicalPath();
				String wav = txt.replace(".txt", ".wav");
				String mp3 = txt.replace(".txt", ".mp3");

				txt2mp3(txt, wav, mp3);
			}
			
			print("Generating Cue Points...");
			// 3 - Write CuePoints to file
			int[] cuePoints = generateCuePoints();

			// 4 Write Cue Points to Index HTML file
			writeCuePointsToFile(cuePoints);

			// 5 - Wrap all mp3 into one audio file
			mp3wrap();

		} catch (IOException ex) {
			System.out.println(ex.toString());
		}
	}

	private static File[] getAudioFiles() {
		// System.out.println("Getting Audio files...");
		File f = new File(AUDIO_PATH); // Captions directory
		// System.out.println("Audio path -> " + f.getAbsolutePath());

		FilenameFilter audioFilter = new FilenameFilter() {
			public boolean accept(File dir, String name) {
				String regEx = "aud-?\\d?\\d?\\.txt";
				return (name.matches(regEx));
			}
		};

		File[] files = f.listFiles(audioFilter);

		return files;
	}

	private static void txt2mp3(String txt, String wav, String mp3) {

		try {

			// TODO find Empty file and add default silence of 1 second

			// System.out.println("Starting Balabolka...");
			// -p pitch in a range of -10 to 10 (the default is 0)
			// -s sets the speed in a range of -10 to 10 (the default is 0)
			// -v sets the volume in a range of 0 to 100 (the default is 100)
			// -n voice_name
			// -e Sets the length of pauses between sentences (in milliseconds).
			// The default is 0.
			// -a Sets the length of pauses between paragraphs (in
			// milliseconds). The default is 0.
			// --silence-begin Sets the length of silence at the beginning of
			// the audio file (in milliseconds). The default is 0.
			// --silence-end Sets the length of silence at the end of the audio
			// file (in milliseconds). The default is 0.
			// -f Sets the name of input text file.

			/*
			 * String command1 =
			 * "bb -p 0 -s 0 -v 100 -n Brian -e 300 -a 500 --silence-begin 400 --silence-end 400 -f "
			 * + txt + " -w " + wav;
			 */

			String command1 = "bb -p 0 -s 0 -v 100 -n Brian -e 300 -a 500 --silence-begin 1000 --silence-end 200 -f "
					+ txt + " -w " + wav;

			Process process1 = Runtime.getRuntime().exec(command1);
			
			// print("Generating wav file -> " + wav.substring(wav.length()-11,
			// wav.length()));
			printProcessOutput(process1);
			process1.waitFor();

			String command2 = "lame -h --silent " + wav + " " + mp3;
			Process process2 = Runtime.getRuntime().exec(command2);
			printProcessOutput(process2);
			
			process2.waitFor();

			// print("Deleting wav file");
			new File(wav).delete();

		} catch (IOException ex) {
			System.out.println(ex);
		} catch (InterruptedException ex) {
			System.out.println(ex);
		}

	}

	private static int[] generateCuePoints() {
		int results[] = null;
		// print("Generating Cue Points");
		BufferedReader b = null;
		StringBuffer t = null;

		try {
			String command = "mp3info -p %S, " + AUDIO_PATH + "*.mp3";
			Process process = Runtime.getRuntime().exec(command);
			BufferedReader in = new BufferedReader(new InputStreamReader(
					process.getInputStream()));

			String line = in.readLine();
			String delims = "[,]";
			String[] tokens = line.split(delims);

			t = new StringBuffer();

			t.append(tokens.length + " tokens\n");
			t.append("tokens: ");

			for (int i = 0; i < tokens.length - 1; i++) {
				t.append(tokens[i] + ",");
			}

			t.append(tokens[tokens.length - 1] + "\n");

			int values[] = new int[tokens.length];

			for (int i = 0; i < tokens.length; i++) {
				values[i] = Integer.parseInt(tokens[i]);
			}

			results = new int[tokens.length];
			results[0] = values[0];

			int sum = values[0];

			for (int i = 1; i < tokens.length; i++) {
				sum = sum + values[i];
				results[i] = sum;
			}

			t.append("cue Points :");

			for (int i = 0; i < results.length - 1; i++) {
				t.append(results[i] + ",");
			}
			t.append(results[results.length - 1] + "\n");

			System.out.print(t.toString());

		} catch (FileNotFoundException ex) {
			System.out.println(ex);
		} catch (IOException ex) {
			System.out.println(ex);
		} finally {
			try {
				if (b != null)
					b.close();
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}

		return results;

	}

	static void writeCuePointsToFile(int[] cuePoints) {
		print("Writing Cue Points to Cue file");
		if (cuePoints.length < 1)
			return;

		try {
			File file = new File(CUE_FILE);
			if (file.exists()) {
				file.delete();
			}

			String cueString = "";

			for (int i : cuePoints) {
				cueString = cueString + i + ",";
			}

			// remove the last comma
			cueString = cueString.substring(0, cueString.length() - 1);

			BufferedWriter bw = new BufferedWriter(new FileWriter(file));
			bw.write("[" + cueString + "]");
			bw.close();

		} catch (Exception ex) {
			System.out.println(ex.toString());
		}
	}

	private static void mp3wrap() {

		// mp3wrap -v ..\\audio.mp3 ..\\audio\\audio*.mp3
		String command1 = "mp3wrap -v ..\\audio.mp3 " + AUDIO_PATH + "aud*.mp3";

		try {
			Process process = Runtime.getRuntime().exec(command1);
			// print("Wrapping mp3 files");
			printProcessOutput(process);
			process.waitFor();
		} catch (IOException ex) {
			System.out.println(ex);
		} catch (InterruptedException ex) {
			System.out.println(ex);
		}
	}

	private static void deleteMp3Files(File[] files) {
		print("Deleting mp3 files");
		File f;
		try {
			for (File file : files) {
				String txt = file.getCanonicalPath();
				String mp3 = txt.replace(".txt", ".mp3");
				f = new File(mp3);
				if (f.exists()) {
					f.delete();
					//System.out.println("<<<<<<<<<<<<<" + f.getName() + "is deleted");
				}
			}
		} catch (IOException ex) {
			System.out.println(ex.toString());
		}

	}

	private static void cleanUp() {
		print("Cleaning up...");

		String mp3 = "..\\audio_MP3WRAP.mp3";

		/*File mp3File = new File(mp3);

		if (!Util.isNullObject(mp3) && mp3File.delete()) {
			print(mp3 + " is deleted");
		}*/
		
		if (new File(mp3).delete()){
			print(mp3 + " is deleted");
		}

		if (new File(CUE_FILE).delete()) {
			print(CUE_FILE + " is deleted");
		}
		// Delete mp3 files from audio folder
		deleteMp3Files(files);

	}

	private static void print(String msg) {
		System.out.println("<< " + msg + " >>");
	}

	private static void printProcessOutput(Process p) {
		try (BufferedReader in = new BufferedReader(new InputStreamReader(
				p.getInputStream()))) {

			String line = null;
			while ((line = in.readLine()) != null) {
				System.out.println(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
